package com.cloud.point.concurrent.juc;

import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.AbstractQueuedSynchronizer;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;

import lombok.extern.slf4j.Slf4j;

/**
 * AQS 的使用
 *
 * @author 24373
 * @version 1.0
 * @date 2024-06-22 11:00
 */
@Slf4j
public class TestAQS {

    public static void main(String[] args) {
        TLock lock = new TLock();
        new Thread(() -> {
            log.info("{}等待加锁", Thread.currentThread().getName());
            lock.lock();
            log.info("{}加锁", Thread.currentThread().getName());
            try {
                log.info("{}获取锁", Thread.currentThread().getName());
                TimeUnit.SECONDS.sleep(2);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            } finally {
                lock.unlock();
            }
        }, "t1").start();
        new Thread(() -> {
            log.info("{}等待加锁", Thread.currentThread().getName());
            lock.lock();
            log.info("{}加锁", Thread.currentThread().getName());
            try {
                log.info("{}获取锁", Thread.currentThread().getName());
            } finally {
                lock.unlock();
            }
        }, "t2").start();
    }

}

@Slf4j
class TLock implements Lock {

    private final MySync sync = new MySync();

    /**
     * 加锁（不成功进入等待队列）
     */
    @Override
    public void lock() {
        // 尝试加锁，不成功进入等待队列
        sync.acquire(1);
    }

    /**
     * 加锁可打断
     */
    @Override
    public void lockInterruptibly() throws InterruptedException {
        sync.acquireInterruptibly(1);
    }

    /**
     * 尝试加锁（一次）
     */
    @Override
    public boolean tryLock() {
        return sync.tryAcquire(1);
    }

    /**
     * 尝试加锁，带超时
     */
    @Override
    public boolean tryLock(long time, TimeUnit unit) throws InterruptedException {
        return sync.tryAcquireNanos(1, unit.toNanos(time));
    }

    /**
     * 解锁
     */
    @Override
    public void unlock() {
        /**
         * 相对于 tryRelease() 方法，它除了置空线程拥有者与改变资源状态外，还会唤醒等待队列中的线程
         */
        sync.release(1);
    }

    @Override
    public Condition newCondition() {
        return sync.newCondition();
    }

    /**
     * 实现独占锁
     */
    class MySync extends AbstractQueuedSynchronizer {

        /**
         * 获取锁
         * state 属性表示资源的状态
         * arg 参数用于判断可重入锁的计数操作
         */
        @Override
        protected boolean tryAcquire(int arg) {
            // 目前实现的是不可重入锁，不需要判断arg
            if (compareAndSetState(0, 1)) {
                log.info("{}获得锁", Thread.currentThread().getName());
                //设置线程拥有者
                setExclusiveOwnerThread(Thread.currentThread());
                return true;
            }
            return false;
        }

        @Override
        protected boolean tryRelease(int arg) {
            setExclusiveOwnerThread(null);
            // state属性是 volatile ，放后面加入写屏障可以保证有序性
            setState(0);
            return true;
        }

        @Override
        protected boolean isHeldExclusively() {
            return getState() == 1;
        }

        public Condition newCondition() {
            return new ConditionObject();
        }

    }

}

